home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 85 / CD Temático 40 Febrero 2004.iso / DOS / ntfs / dos / readdisk.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-15  |  16.5 KB  |  554 lines

  1. /* ReadDisk, 11 June 1999                *
  2.  * Christophe GRENIER                    *
  3.  * grenier@nef.esiea.fr                    *
  4.  * http://www.esiea.fr/public_html/Christophe.GRENIER/    *
  5.  * Based on readdisk.c from LRead by Werner Zimmermann     */
  6. #include <stdio.h>
  7. #include <string.h>
  8. #define STDERR stdout   /* Tell, where you'd like your error messages*/
  9. #include <stdlib.h>
  10. /*
  11. #include <bios.h>
  12. #include <dos.h>
  13. #include <conio.h>
  14.  */
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include <fcntl.h>
  18. #include "types.h"
  19. #include "common.h"
  20. #include "hdaccess.h"
  21. #include "readdisk.h"
  22. #include "fnctdsk.h"
  23. //#include "km.h"
  24. enum {STATE_DIRTY, STATE_READ, STATE_WRITE};
  25. typedef struct {
  26.   int C;
  27.   int H;
  28.   int S;
  29.   int state;
  30. } t_cached;
  31. #define cache_size 500    // cache size in sectors => 256 Ko
  32. #define Nb_SuccSect 16    // 8 Ko per read
  33. #define DISK_BLOCK_SIZE 512
  34. unsigned char cache_buffer[cache_size][DISK_BLOCK_SIZE];
  35. t_cached cache_lst[cache_size];
  36.  
  37. dword RS_offset;
  38.  
  39. void *MALLOC(size_t size)
  40. { void *p=NULL;
  41.   if (size)
  42.   { p=malloc(size);
  43.   }
  44.   return(p);
  45. }
  46.  
  47.   void FREE(void *block)
  48. { if (block!=NULL)
  49.   { free(block);
  50.   }
  51. }
  52.  
  53. /*Global Defines, but nothing to edit for users*/
  54. #define READ_CMD  2       /*Disk Read  Command, do *NOT* change!!!*/
  55. #define WRITE_CMD 3       /*Disk Write Command, do *NOT* change!!!*/
  56. #define PARA_CMD  8       /*Disk Identify Command, do *NOT* change!!!*/
  57.  
  58. #define NONE      0
  59. #define OK        1
  60. #define EXTENDED  2
  61. #define END_TABLE 3
  62.  
  63. #define INIT         0
  64. #define KEEP_BUF     1    /*used to control free(buf) in read_inode()*/
  65. #define RELEASE_BUF  2
  66. #define KILL_BUF     3
  67.  
  68. /* globals */
  69. t_param_disk disk_car;
  70. unsigned long start;                    /*logical block address(LBA) of your partition*/
  71. unsigned long num_sect;                 /*total # of sectors of your partition*/
  72. unsigned long pos_off;
  73. unsigned int  disk_no;           /*DOS' disk #, eg. 0x80=first harddisk*/
  74. unsigned int  part_no;           /*# of your partition*/
  75. int IN_DEV=0;                         /* holds the open input dev */
  76.  
  77.  
  78. int name2diskno(char *name)
  79. {
  80.   if (strstr(name,"/dev/hda"))     /* figure out disk number for DOS*/
  81.     return 0x80;
  82.   else if (strstr(name,"/dev/hdb"))
  83.     return 0x81;
  84.   else if (strstr(name,"/dev/hdc"))
  85.     return 0x82;
  86.   else if (strstr(name,"/dev/hdd"))
  87.     return 0x83;
  88.   else if (strstr(name,"/dev/sda"))
  89.     return 0x80;
  90.   else if (strstr(name,"/dev/sdb"))
  91.     return 0x81;
  92.   else if (strstr(name,"/dev/fd0"))
  93.     return 0;
  94.   else if (strstr(name,"/dev/fd1"))
  95.     return 1;
  96.   printf("Unknown Drive Specification: %s\n",name);
  97.   return -1;
  98. }
  99.  
  100. /*Convert Logical Block Number (LBA) adress to
  101.   Cylinder-Head-Sector (CHS) address
  102.   DOS and Linux software doesn't care about heads, sectors, cylinders, ie.
  103.   your harddisk's hardware details and therefore works with LBA, but if you
  104.   want to access your harddisk via the BIOS, you have to call the BIOS rou-
  105.   tines with CHS addresses.
  106.  */
  107.  
  108. void convert(unsigned long x, unsigned int *head, unsigned int *track, \
  109.     unsigned int *sector, unsigned int *offset)
  110. { unsigned long logicsect, absolsect;
  111.  
  112.   logicsect =  x >> 9;                 /*divide by 512= harddisk sector size*/
  113.   *offset   =  x & 0x1FF;              /*modulo 512*/
  114.   absolsect =  logicsect+start;
  115.  
  116.   *track    =  absolsect / (disk_car->CHS.sector * (disk_car->CHS.head+1));
  117.   *head     = (absolsect / disk_car->CHS.sector) % (disk_car->CHS.head+1);
  118.   *sector   = (absolsect % disk_car->CHS.sector) + 1;
  119.  
  120.   if (absolsect > start+num_sect)
  121.   { fprintf(STDERR,"You cannot access ABOVE the partition.\n");
  122.     exit(-1);
  123.   }
  124. }
  125.  
  126. /* Christophe GRENIER 26/01/99 */
  127. int pos_read=0;
  128. unsigned long int sect_cached=0,sect_read=0;
  129.  
  130. int do_read(int disk_no,int head,int cyl, int sect)
  131. {
  132.   /*With floppys there are problems when trying to read beyond the last sector
  133.     of a cylinder. So we try to deal with that. I never had this problem with
  134.     harddisks, most likely, because my harddisks work in lba-mode, translating
  135.     heads/sector/cylinder on their own. If we get read errors (rd!=0), the
  136.     following piece of code needs to be improved
  137.    */
  138.   static int pos=-1;
  139.   unsigned int rc=0, x,i,nb_sect;
  140. #ifdef DEBUG_READDISK
  141.   fprintf(STDERR,"  do_read start - head:%u cyl:%u sect:%u  no_sect:%lu\n",head,cyl,sect,num_sect);
  142.   fflush(stderr);
  143. #endif
  144.   sect_read++;
  145.   if(pos==-1)    /* Init cache */
  146.     for(x=0;x<cache_size;x++) cache_lst[x].state=STATE_DIRTY;
  147. #ifndef NOCACHE
  148.   for(x=0;x<cache_size;x++)
  149.   {
  150.     if( cache_lst[x].state==STATE_READ&&    // Search in cache
  151.     cache_lst[x].C==cyl&&
  152.     cache_lst[x].H==head&&
  153.     cache_lst[x].S==sect)
  154.     {
  155. #ifdef DEBUG_READDISK
  156.       printf("Cached\n");
  157. #endif
  158.       sect_cached++;
  159.       pos_read=x;
  160.       return 0;
  161.     }
  162.   }
  163. #endif
  164.   if(++pos>=cache_size) pos=0;    /* circular method (simple but not the best) */
  165.   nb_sect=cache_size-pos<Nb_SuccSect?cache_size-pos:Nb_SuccSect;
  166.   if(nb_sect+sect>disk_car->CHS.sector)    /* stay carrefully */
  167.     nb_sect=disk_car->CHS.sector-sect+1;    /* on the same cylinder and head */
  168.   //  nb_sect=1;
  169.   {
  170.     t_diskext partition=MALLOC(sizeof(*partition));
  171.     partition->disk=disk_no;
  172.     partition->start.cylinder=cyl;
  173.     partition->start.head=head;
  174.     partition->start.sector=sect;
  175.     if(hd_read2(disk_car,nb_sect,&cache_buffer[pos],partition))
  176.     {
  177.       printf("\nErreur de lecture");
  178.     }
  179.     FREE(partition);
  180.   }
  181.   pos_read=pos;
  182.   for(i=0;i<nb_sect;i++)
  183.   {
  184.     cache_lst[pos].state=STATE_READ;
  185.     cache_lst[pos].C=cyl;
  186.     cache_lst[pos].H=head;
  187.     cache_lst[pos].S=sect;
  188.     sect++;
  189.     /* Not necessairy
  190.        if(++sect>disk_car->CHS.sector)
  191.        { sect=1;
  192.        if(++head>=HEADS)
  193.        {    head=0;cyl++; }
  194.        }
  195.      */
  196.     pos++;
  197.   }
  198. #ifdef DEBUG_READDISK
  199.   fflush(stdout);
  200.   fflush(stderr);
  201.   printf("\ndo_read end");
  202.   fflush(stdout);
  203. #endif
  204.   return rc;
  205. }
  206.  
  207. int readdisk( unsigned char *buf, unsigned long loc, unsigned long size )
  208. {
  209.   unsigned int head,cyl,sect,offset;
  210.   unsigned int no_sect;
  211.   unsigned int i; //,rc;
  212.   unsigned char *temp;
  213. #ifdef DEBUG_READDISK
  214.   printf("--------Executing 'readdisk'--*buf:%u--size:%lu--loc:%lu\n",*buf,size,loc);
  215.   fflush(stdout);
  216. #endif
  217.  
  218.   convert (loc,&head,&cyl,§,&offset);
  219.  
  220.   no_sect= (offset+size)>>9;
  221.   if ((offset+size)&0x1FF) no_sect++;
  222.   if (no_sect<2)
  223.   {
  224.     if (disk_no<128) no_sect=1;     /*with floppys: minimum read is 1 sector*/
  225.     else             no_sect=2;        /*with harddisks:               2 sectors*/
  226.   }
  227.   temp=(unsigned char *) MALLOC(no_sect*512);
  228.   for(i=0;i<no_sect;i++)
  229.   {
  230. #ifdef DEBUG_READDISK
  231.     printf("%d/%d->",i+1,no_sect);
  232.     fflush(stdout);
  233. #endif
  234.     if(do_read(disk_no,head,cyl,sect)) return 0;
  235.     memcpy(&temp[i*DISK_BLOCK_SIZE],&cache_buffer[pos_read],DISK_BLOCK_SIZE);
  236.     if(++sect>disk_car->CHS.sector)
  237.     { sect=1;
  238.       if(++head>disk_car->CHS.head)
  239.       {    head=0;cyl++; }
  240.     }
  241.   }
  242.   memcpy(buf,&temp[offset],size);
  243.   FREE(temp);
  244. #ifdef DEBUG_READDISK
  245.   printf("--------readdisk end\n");
  246.   fflush(stdout);
  247.   printf("readdisk ");
  248.   for(i=0;i<0x10;i++)
  249.     printf("%02X ",*(char*)(buf+i));
  250.   printf("\n");
  251.   fflush(stdout);
  252. #endif
  253.   return size;
  254. }
  255.  
  256. int writedisk( unsigned char *buf, unsigned long loc, size_t size )
  257. {
  258.   unsigned int head,cyl,sect,offset;
  259.   unsigned int rc=0, x;
  260.   unsigned long no_sect;
  261.   for(x=0;x<cache_size;x++) cache_lst[x].state=STATE_DIRTY;
  262.   convert (loc,&head,&cyl,§,&offset);
  263.   if((offset==0)&&(size%512==0))
  264.   {
  265.     t_diskext partition=MALLOC(sizeof(*partition));
  266.     no_sect=size>>9;
  267.     partition->disk=disk_no;
  268.     partition->start.cylinder=cyl;
  269.     partition->start.head=head;
  270.     partition->start.sector=sect;
  271.  
  272.     if(hd_write2(disk_car,no_sect,buf,partition))
  273.     {
  274.       printf("\nErreur de lecture");
  275.     }
  276.     FREE(partition);
  277.   }
  278.   else
  279.   {
  280.     static unsigned char *temp;
  281.     t_diskext partition=MALLOC(sizeof(*partition));
  282. #ifdef DEBUG_READDISK
  283.     printf("\nExperimental Write");
  284.     fflush(stdout);
  285. #endif
  286.     no_sect= (size+loc%512) >> 9;
  287.     if(size+loc%512!=0)
  288.       no_sect++;
  289.     temp=(unsigned char *) MALLOC(no_sect*512);
  290.     readdisk(temp, (loc>>9)*512,no_sect*512);   /* in fact, only need beginning and ending*/
  291.     memcpy(&temp[offset],buf,size);     /* no ending NULL */
  292.     partition->disk=disk_no;
  293.     partition->start.cylinder=cyl;
  294.     partition->start.head=head;
  295.     partition->start.sector=sect;
  296.     if(hd_write2(disk_car,no_sect,temp,partition))
  297.     {
  298.       printf("\nErreur de lecture");
  299.     }
  300.     FREE(partition);
  301.     FREE(temp);
  302.   }
  303.   if (rc==0)
  304.     return size;
  305.   else
  306.   {
  307.     fprintf(STDERR,"Error %x in Write Disk - loc:%lu head:%u cyl:%u sect:%u  no_sect:%lu\n",rc,loc,head,cyl,sect,num_sect);
  308.     return 0;
  309.   }
  310. }
  311.  
  312. off_t lseek_dev(int fd, off_t offset, int whence)
  313. {
  314.   switch(whence)
  315.   {
  316.     case(SEEK_SET):
  317.       pos_off=offset;
  318.       break;
  319.     case(SEEK_CUR):
  320.       pos_off+=offset;
  321.       break;
  322.     case(SEEK_END):
  323.       pos_off=num_sect+offset;
  324.       break;
  325.   }
  326.   return pos_off;
  327. }
  328.  
  329. ssize_t read_dev(int fd, void *buffer, size_t length)
  330. {
  331.   ssize_t tmp;
  332. #ifdef DEBUG_READDISK
  333.   printf("Read dev - length %ld\n",length);
  334. #endif
  335.   tmp=readdisk(buffer,pos_off,length);
  336.   pos_off+=length;
  337.   return tmp;
  338. }
  339.  
  340. ssize_t write_dev(int fd, void *buffer, size_t length)
  341. {
  342.   ssize_t tmp=writedisk(buffer,pos_off,length);
  343.   pos_off+=length;
  344.   return tmp;
  345. }
  346.  
  347. /*This procedure looks for your partition.
  348.   You have to specify the disk to search via the -s or -f command
  349.   line switch, specification is done in Linux 'style', your specification is
  350.   converted into a DOS 'style' specification in global variables disk_no and
  351.   part_no, eg.:
  352.  
  353.   /dev/hdaX           first harddisk        disk_no=0x80
  354.   /dev/hdbX           second harddisk               0x81
  355.   /dev/fd0            first floppy disk             0x00
  356.   /dev/fd1            second floppy disk            0x01
  357.  
  358.   If you do not specify a partition number, i.e. if X is a space, the procedure
  359.   will search the four entrys of the partition table for a primary
  360.   partition, if it finds one, it will use it. If it does not find a primary
  361.   partition, it searches for an DOS extended partition, read's the
  362.   DOS extended partition's table and searches it for a partition.
  363.   As DOS extended partitions may contain an unlimited number of 'logical drives',
  364.   this search is recursively until we find a "good type" partition or until we
  365.   reach the end of the tables.
  366.  
  367.   If you additionally specify a partition number, i.e. set X to 5, for each
  368.   NTFS partition we find we also check, if its the specified partition num-
  369.   ber. If not, we continue the search of the partition table. The partition
  370.   number is transfered to the procedure via global variable part_no.
  371.  */
  372.  
  373. int examine_drive(uint disk_num, uint part_num,int open_mode,int debug)
  374. { int i,k,kfound=0,p=0,ptemp=0;
  375.   static unsigned char *buf;
  376.   char found=NONE;
  377.   unsigned char run[4][16];
  378.   t_diskext partition=MALLOC(sizeof(*partition));
  379.   if(disk_car==NULL)
  380.     disk_car=MALLOC(sizeof(*disk_car));
  381.  
  382.   RS_offset=1;
  383.   partition->disk=disk_num;
  384.   partition->start.cylinder=0;
  385.   partition->start.head=0;
  386.   partition->start.sector=1;
  387.   part_no=part_num;
  388.   buf=(unsigned char *) MALLOC(512);
  389.   start=0;
  390.   disk_car->disk=disk_num;
  391.   if(hd_identify(disk_car,debug))
  392.     return 1;
  393.   if ((partition->disk==0)||(partition->disk==1))       /*Is it a floppy drive? 0=A:  1=B:*/
  394.   { start     = (long) 0;             /*floppy's do not have partitions*/
  395.     num_sect  = (disk_car->CHS.head+1)*disk_car->CHS.sector*(disk_car->CHS.cylinder+1);
  396.     FREE(partition);
  397.     FREE(buf);
  398.     return 0;
  399.   }
  400.  
  401.   /* read the partition table from the first hard drive, partition table starts at CHS=0 0 1*/
  402.   if(hd_read2(disk_car,1,buf,partition))
  403.     return 1;  /*if the BIOS can't read the partition table*/
  404.   for (k=0;k<4;k++)             /*Search the Primary Partition Table for a Linux partition*/
  405.   {
  406.     for (i=0;i<16;i++)        /*The partition table has 4 entrys with 16 bytes per entry*/
  407.     run[k][i] = buf[446+(k*16)+i]; /*it starts at byte 446 in the harddisk's first sector*/
  408.     if ((run[k][4]==0x7)||(run[k][4]==0x17))
  409.     { if ((part_no==0)||(k==part_no-1))  /*we found a good partition, but does it have the correct partition number?*/
  410.       { found=OK;
  411.     kfound=k;                      /*yes*/
  412.       }
  413.       else
  414.     ptemp=k+1;                      /*no*/
  415.     }
  416. #ifdef DEBUG
  417.     printf("found %d, kfound %d\n",found,kfound);
  418. #endif
  419.   }
  420.   if (found!=OK)             /*We haven't found a "good type" primary partition, so we search for an extended partition*/
  421.   { for (k=0;k<4;k++)
  422.     {
  423.       if ((run[k][4]==0x05)||(run[k][4]==0x0F))  /*0x05 is the signature for extended partitions*/
  424.       { found=EXTENDED;
  425.     p=5;              /*Extended partitions start at /dev/hd?5*/
  426.     kfound=k;
  427.       }
  428. #ifdef DEBUG
  429.       printf("found ext %d, kfound %d\n",found,kfound);
  430. #endif
  431.     }
  432.   }
  433.   if(found!=NONE)
  434.     entree2partition(disk_car,1,partition,run[kfound],STATUS_PRIM);
  435.   if (found==EXTENDED)          /*Searching extended partition table*/
  436.   {
  437.     dword pos=get_SR_part(disk_car,partition);
  438.     do
  439.     {
  440.       printf("p=%d\n",p);
  441.       found=NONE;
  442.       entree2partition(disk_car,pos,partition,run[kfound],STATUS_EXT_IN_EXT);
  443.       if(hd_read2(disk_car,1,buf,partition))
  444.     return 1;
  445.       if((buf[0x1FE]!=0x55)||(buf[0x1FF]!=0xAA))
  446.     return 1;
  447.       /*get the partitions CHS address from the partition table*/
  448.       /*Check extended Partition Table, same game as with the primary table*/
  449.       /*The extended partition table has 2 entrys with 16 bytes per entry*/
  450.       /*where one entry can be another extended partition*/
  451.       for (k=0;k<2;k++)
  452.       { for (i=0;i<16;i++)
  453.     run[k][i] = buf[446+(k*16)+i];
  454.     if ((run[k][4]==0x05)||(run[k][4]==0x0F))
  455.     { found=EXTENDED;            /*hurrah, another extended partion*/
  456.       kfound=k;
  457.       p++;
  458.     }
  459.     if ((run[k][4]==0x7)||(run[k][4]==0x17))        /*hurrah */
  460.     { if ((part_no==0)||(p==part_no)) /*does it have the correct partition number?*/
  461.       { found=OK;
  462.         kfound=k;                   /*yes*/
  463.       }
  464.       else
  465.         ptemp=p;                    /*no*/
  466.     }
  467.     if(RS_offset==1)
  468.       RS_offset=pos;
  469.       }
  470. //    } while ((run[1][4]!=0)   && (found!=OK) && (buf[510]==0x55) && (buf[511]==0xAA));
  471.     } while ((run[1][4]!=0)   && (found==EXTENDED) && (buf[510]==0x55) && (buf[511]==0xAA));
  472.     if(found!=NONE)
  473.       entree2partition(disk_car,pos,partition,run[kfound],STATUS_LOG);
  474.   }
  475.     /*our search continues until either -we found the last entry which's signature is 0
  476.       or     -we found the right good partition
  477.       or     -the sector is not a partition table (signature 0xAA55*/
  478.  
  479.     if (found!=OK)   /*if we finally did not find the partition*/
  480.     {
  481.       if (ptemp>0)
  482.     fprintf(STDERR,"Found at partition number %i\n",ptemp);
  483.       return 2;
  484.     }
  485.  
  486.     /*if we reach this point, we've found the right partition*/
  487.     /*get the partitions CHS address from the partition table*/
  488.     start=get_LBA_part(disk_car,partition);
  489.     num_sect=partition->part_size;
  490. #ifdef DEBUG
  491.     printf("start %ld num_sect %ld\n",start,num_sect);
  492. #endif
  493.     FREE(partition);
  494.     FREE(buf);
  495.     return 0;
  496. }
  497.  
  498. int open_dev(char *name , int open_mode)
  499. {
  500.   int    tmp;
  501.   char   *temp;
  502.   unsigned int  disk_no;
  503.   unsigned int  part_no;
  504.   int debug=0;
  505.   if (strlen(name)==0)
  506.   {
  507.     for(disk_no=0x80;disk_no<0x84;disk_no++)
  508.       if((tmp=examine_drive(disk_no,0, open_mode,debug))!=2)
  509.     break;
  510.     if(tmp!=0)
  511.     {
  512.       fprintf(STDERR,"\nNo partition found");
  513.       return -1;
  514.     }
  515.   }
  516.   else
  517.   {
  518.     if((disk_no=name2diskno(name))==-1)
  519.       return -1;
  520.     if (disk_no>=0x80)  /*do it only for harddisks ???*/
  521.     {
  522.       if (strstr(name,"dev/hd"))
  523.     temp=strtok(name,"/dev/hd");
  524.       else
  525.       { temp=strtok(name,"dev/sd");
  526.     fprintf(STDERR,"SCSI drive support is experimental\n");
  527.       }
  528.       part_no=temp[1]-0x30;                     /*convert char to int*/
  529.       if ((part_no<1)||(part_no>9))
  530.     part_no=0;
  531.     }
  532.     else
  533.       part_no=1; /*on floppy disks we only have one partition*/
  534.     tmp=examine_drive(disk_no,part_no,open_mode,debug);
  535.     switch(tmp)
  536.     {
  537.       case 1:
  538.     fprintf(STDERR,"Error Reading Partition Table on %s\n",name);
  539.     break;
  540.       case 2:
  541.     fprintf(STDERR,"Could not find partition on %s\n",name);
  542.     break;
  543.     }
  544.     if(tmp!=0)
  545.     {
  546.       fprintf(STDERR,"//hdx[y]/path ,\n"
  547.       "where x=a,b,... is the harddisk and\n"
  548.       "y=1,2,... (may be omitted) is your partition number\n");
  549.       return -1;
  550.     }
  551.   }
  552.   return 10;
  553. }
  554.